package com.wili.extract_srcFile.java;
import java.io.Serializable;
import java.lang.reflect.Executable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Stack;
import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.c.Ca;
import com.wili.c.Class9;
import com.wili.c.Misc9;
import com.wili.c.Src9;
import com.wili.c.Str9;
import com.wili.c.asm.FieldItem;
import com.wili.extract_srcFile.demo.Cls51;
import com.wili.insertLog.LogConst;
/**
 *  Parse sourceCode: parse class member range infomation as tree node.
 *  read class|innerClass|interface|enum as tree. ignores Local class 
 *  @see this{@link #testFiles()}
 * @author weila 2021年2月17日
 */
public class RootOfClsMember implements Serializable {//类成员的嵌套范围统计。
	private static final long serialVersionUID = 1L;

	public final ImportMap importMap;

	public final String fileSt0, fileSt;

	public final Class<?> clazz;

	public final List<Integer> newLineIndexList;

	final ClsMemberRangeList memberRanges;

	/**
	 *	.该文件下所有类的起止信息
	 */
	final Map<Class<?>, ClsRange> clsRangeMap = new HashMap<>();// new TreeMap<>(Class9.CompByName);

	final Map<Integer, Integer> lrMap = new TreeMap<>();

	private Stack<Integer> lrStack = new Stack<>();

	final String clsName;

	final List<ClsRange> sons = new ArrayList<>(3);

	final List<int[]> commnetRangeList;

	public Class<?> classOfName(String name) {
		Class<?> ret = importMap.clsMap.get(name);
		if (this.clazz.getSimpleName().equals(name))
			return this.clazz;
		String pname = this.clazz.getPackageName();
		ret = Class9.classOfName(pname + "." + name, -1);
		if (ret != null)
			importMap.clsMap.put(name, ret);
		return ret;
	}

	public List<ClsMemberRange> getClsMemberRangeList() {
		return memberRanges.list;
	}

	public Map<Class<?>, ClsRange> getClsRangeMap() {
		return clsRangeMap;
	}

	int lineNoAt(int index) {
		return Misc9.lineNoAt(index, newLineIndexList);
	}

	MethodRange findMethodRange(int lineNo) {
		int ind = indexOfMemberRange(lineNo);
		if (ind == -1)
			return null;
		Ca.pause();
		ClsMemberRange ret = this.memberRanges.get(ind);
		if (ret instanceof ClsRange)
			return MethodRange.newMethodRange((ClsRange) ret);//无参构造且未明示在源码中
		if (ret instanceof MethodRange)
			return (MethodRange) ret;
		return null;
	}

	MethodRange findMethodRange(Class<?> cls, Executable method) {
		ClsRange crange = this.clsRangeMap.get(cls);
		String name = method.getName();
		Class<?>[] types = method.getParameterTypes();
		int ind = indexOfMemberRange(crange.aLineNo);
		Ca.asert(ind >= 0, method);
		MethodRange maybeRet = null;
		f1: for (int i = ind; i < memberRanges.size(); i++) {
			ClsMemberRange mem = this.memberRanges.get(i);
			if (mem.aStart > crange.aEnd)
				return maybeRet;
			if (mem instanceof MethodRange) {
				MethodRange md = (MethodRange) mem;
				if (!cls.equals(md.cls))
					continue;
				if (md.name.equals(name)) {
					//若参数类型名都匹配，则返回函数
					if (md.typeNames.length != types.length)
						continue;
					for (int j = 0; j < types.length; j++) {
						if (!types[j].getSimpleName().equals(md.typeNames[j])) {
							if (maybeRet != null)
								continue f1;
							maybeRet = md;//eg. Comparable的泛型继承，可能有具体参数，但反射时参数类型是Object,不直接匹配
							continue f1;
						}
					}
					return md;
				}
			}
		}
		return maybeRet;
	}

	public int indexOfMemberRange(int lineNo) {
		/*
			wili.c.AllotInt9$TwoBitIteratorConcator.next() lineNO should be 172, not 1!
		 */
		int ind = this.memberRanges.indexOfMember_byLineNo(lineNo);
		if (ind < 0) {
			int ind2 = -(ind + 1) - 1;
			ind = ind2;
			if (ind < 0)
				return -1;
			return ind;
		} else {
			return ind;
		}
	}

	Stack<ClsRange> nodStack = new Stack<>();
	static void log(int opt, Object... msgs) {
		Ca.debug(-1, msgs);
	}
	//static final String MethodHeadPat = "|\n[ \t\\w<\\?>,&\\[\\]]+?([\\w\\$]+)\\(";//方法头也是可以断行的。
	static final String MethodHeadPat = "|\n[^@\n=\\(\\)\\{\\};]+?([\\w\\$]+)\\(";//返回值可含点

	/**
	 * 	类的定义头部。在注释中定义无效，但可以包含注释。
	 */
	static final Pattern clsHead_L_R_Pat = Pattern.compile(//
			"\n[ \t]*(\\w+\\s+)*?(class|interface|enum)\\s+([\\w\\$]+)"//类|接口|枚举
					+ "|(\\s+static\\s+)?[\\{\\}]"//
					+ "|@[^\r\n]+"//annotation
					+ "|\n[^@;\\(\\)\\{\\}=]+="//属性定义时赋初值，等号后可能有嵌套括号；eg. Test[] testList = {,...
					+ "|\n[^@;\\(\\)\\{\\}]+;"//属性定义
					+ MethodHeadPat
	//
	);

	ClsRange curClsRange = null;
	//static final Map<Class<?>, Class<?>> cMap_newToOld = new HashMap<>();
	/**
	 * @param fileName.
	 * @param fileSt  sourceCode of a javaFile, without quotation and notation content.
	 * @param skipComment.
	 */
	public RootOfClsMember(Class<?> cls, String fileSt, boolean skipComment) {
		this.importMap = new ImportMap(fileSt);
		this.memberRanges = new ClsMemberRangeList(cls);
		this.clazz = cls;
		this.clsName = cls.getSimpleName();
		this.newLineIndexList = Misc9.indexListOfLines(fileSt);
		this.fileSt0 = fileSt;
		if (cls.equals(FieldItem.class))
			Ca.pause();
		if (cls.equals(ClsMemberRange.class))
			Ca.pause();
		if (skipComment) {
			commnetRangeList = new ArrayList<>();
			fileSt = Src9.replace_javaComment_and_quotes_withSameLengthSpace(fileSt, commnetRangeList);
		} else {
			commnetRangeList = null;
		}
		int times = 0;
		this.fileSt = fileSt;
		//System.out.println(fileSt);
		Matcher mat = clsHead_L_R_Pat.matcher(fileSt);
		int from = 0;
		int pre = from;
		if (cls.equals(Cls51.class))
			Ca.pause();
		while (mat.find()) {
			if (++times == 6)
				Ca.pause();
			String matchedSt = mat.group();
			//
			int lineNo2 = this.lineNoAt(mat.start());
			//System.out.println("lineNO=" + lineNo2);
			if (lineNo2 >= 652)
				Ca.pause();
			if (pre >= mat.start())
				Ca.pause();
			pre = mat.start();
		
			if (++inc == 23)
				Ca.pause();
			if (matchedSt.endsWith("{")) {
				//初始块： 此block非类块，又不在方法内，必是初始块，当跳过。
				if ("".isEmpty()) {
					int ind1 = mat.end() - 1;
					int ind2 = Str9.readBracket('{', '}', fileSt, ind1, fileSt.length());
					memberRanges.add(new InitBlockRange(this, matchedSt.contains("static"), ind1, ind2 + 1));
					mat.region(ind2 + 1, fileSt.length());
					continue;
				}
				lrStack.push(mat.start());
				++curClsRange.leftBraceNo;
				from = mat.end();
				log(1, "findL:", mat.start());
				mat.region(from, fileSt.length());
				continue;
			} else if (matchedSt.equals("}")) {
				//类的终止，因初始块和方法块都不在此处读取
				int leftInd = lrStack.pop();
				lrMap.put(leftInd, mat.start());
				//fileSt.substring(mat.start())
				if ("".isEmpty() || --curClsRange.leftBraceNo == 0) {
					curClsRange.lastMember = this.memberRanges.get(this.memberRanges.size() - 1);
					curClsRange.aEnd = from = mat.end();
					nodStack.pop();
					if (nodStack.isEmpty()) {
						curClsRange = null;
					} else {
						curClsRange = nodStack.peek();
					}
					log(1, "findR.closed:", mat.start());
				} else {
					from = mat.end();
					log(1, "findR:", mat.start());
				}
				mat.region(from, fileSt.length());
				continue;
			} else if (matchedSt.endsWith("(")) {
				//method. 不处理本地类（方法内部定义的类）
				String name = mat.group(5);
				if (name.equals("VlaueClass"))
					Ca.pause();
				log(1, "foundMethod:", name);
				int bodyStart;
				MethodRange range;
				{
					int[] inds = Str9.indexOfAnyChar(fileSt, mat.end(), '{', ';');
					String parmsSt = fileSt.substring(mat.end() - 1, inds[0]);
					parmsSt = parmsSt.substring(0, parmsSt.lastIndexOf(')') + 1);
					memberRanges.add(range = new MethodRange(this, curClsRange.cls, mat, 5, parmsSt));
					if (inds[1] == 1) {//abstrct method.
						range.aEnd = inds[0] + 1;
						mat.region(inds[0] + 1, fileSt.length());
						continue;
					} else {
						bodyStart = inds[0];
					}
				}
				int end = Str9.readBracket('{', '}', fileSt, bodyStart, fileSt.length());
				Ca.asert(end > bodyStart, cls.getName());
				lrMap.put(bodyStart, end - 1);
				range.aEnd = end;
				mat.region(end, fileSt.length());
				continue;
			} else if (matchedSt.startsWith("@")) {
				//annotation
				memberRanges.add(new AnnotationRange(this, mat));
				mat.region(from = mat.end(), fileSt.length());
				continue;
			} else if (matchedSt.endsWith("=")) {
				//属性定义，有赋初值，或有括号嵌套，但必以分号结束。
				int ind = Str9.indexOfChar_skipBracket(';', fileSt, mat.end(), '(', ')', '{', '}');
				Coms26.readClassFields(this, mat.start(), ind + 1);
				mat.region(from = ind + 1, fileSt.length());
				continue;
			} else if (matchedSt.endsWith(";")) {
				//属性定义
				if (matchedSt.trim().length() > 1) {
					if (curClsRange != null) {
						int ind = Str9.indexOfChar_skipBracket(';', fileSt, mat.start(), '(', ')', '{', '}');
						if (!curClsRange.cls.isEnum())
							Coms26.readClassFields(this, mat.start(), ind + 1);
						mat.region(from = ind + 1, fileSt.length());
					} else {
						mat.region(from = mat.end(), fileSt.length());
					}
				}
				continue;
			} else {
				//class
				String name = mat.group(3);
				if (name.equals("Vlaud  eClass"))
					mat.group();
				log(1, "foundClsName:", name);
				from = mat.start() + name.length();
				int sonBodyStart = fileSt.indexOf('{', from);
				//fileSt.substring(sonBodyStart)
				if (sonBodyStart == 99)
					Ca.pause();
				lrStack.push(sonBodyStart);
				{
					ClsRange son;
					if (nodStack.isEmpty()) {
						son = new ClsRange(this, mat, null, name, sonBodyStart);
						this.sons.add(son);
					} else {
						ClsRange dad2 = nodStack.peek();
						son = new ClsRange(this, mat, dad2, name, sonBodyStart);
					}
					if (this.clazz.equals(FieldItem.class))
						Ca.pause();
					if (this.clazz.equals(ClsMemberRange.class))
						Ca.pause();
					if (!son.cls.equals(this.clazz))
						Cont26.ClsToHeadClsMap.put(son.cls, this.clazz);
					curClsRange = son;
					nodStack.push(son);
					log(1, "findM:", sonBodyStart - 1);
					memberRanges.add(son);
				}
				from = sonBodyStart + 1;
				mat.region(from, fileSt.length());
			}
		}
		if ("".isEmpty()) {
			for (int i = 0; i < memberRanges.size(); i++) {
				ClsMemberRange mem = memberRanges.get(i);
				LogConst.asert(mem.aStart < mem.aEnd, i);
				if (i > 0) {
					LogConst.asert(mem.aStart > memberRanges.get(i - 1).aStart, i);
					//同一行可定义多个属性, so maybe '='
					LogConst.asert(mem.aLineNo >= memberRanges.get(i - 1).aLineNo, i);
				}
			}
			//Collections.sort(memberRanges, ClsMemberRange.CompByLineNo);//本是有序的，不需要
			"".isEmpty();
		}
	}
	public static class ImportMap implements Serializable {
		private static final long serialVersionUID = 1L;

		final Map<String, Class<?>> clsMap = new HashMap<>();
		static Pattern pat = Pattern.compile("import\\s+(([\\w+\\$]+\\.)+([\\w\\$]+));$|class \\w+", Pattern.MULTILINE);
		public ImportMap(String fileSt) {
			Matcher mat = pat.matcher(fileSt);
			while (mat.find()) {
				String matSt = mat.group();
				if (matSt.startsWith("class "))
					return;
				String key = mat.group(3);
				Class<?> cls = Class9.forName(mat.group(1), -1);
				if (cls == null)
					continue;
				clsMap.put(key, cls);
			}
		}
	}
	public boolean isFieldAtLineNo(int lineNo) {
		int ind = indexOfMemberRange(lineNo);
		ClsMemberRange ret = this.memberRanges.get(ind);
		return ret instanceof FieldRange;
	}
	static int GenID, inc;
}
